package com.xbongbong.saas.help;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.ConfigConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.MoneyUtil;
import com.xbongbong.pro.enums.errorcodes.InvoiceErrorCodeEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.InvoiceConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.PurchaseInvoiceRelationshipEntity;
import com.xbongbong.saas.domain.entity.ext.PayPlanEntityExt;
import com.xbongbong.saas.domain.entity.ext.PayPlanSheetEntityExt;
import com.xbongbong.saas.domain.entity.ext.PurchaseEntityExt;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.PayPlanEnum;
import com.xbongbong.saas.enums.business.PayRelationshipEnum;
import com.xbongbong.saas.enums.business.PaySheetEnum;
import com.xbongbong.saas.enums.business.PurchaseEnum;
import com.xbongbong.saas.enums.business.PurchaseInvoiceEnum;
import com.xbongbong.saas.model.PayPlanModel;
import com.xbongbong.saas.model.PayPlanSheetModel;
import com.xbongbong.saas.model.PurchaseInvoiceRelationshipModel;
import com.xbongbong.saas.model.PurchaseModel;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.util.InvoiceUtil;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getDoubleOrDefaultFromFormData;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @author 吴峰
 * @date 2021/07/19 14:02
 */
@Component
public class SaasPurchaseInvoiceHelp {

    private static final Logger LOG = LoggerFactory.getLogger(SaasPurchaseInvoiceHelp.class);

    @Resource
    private PayPlanModel payPlanModel;
    @Resource
    private PurchaseModel purchaseModel;
    @Resource
    private PayPlanSheetModel payPlanSheetModel;
    @Resource
    private PurchaseInvoiceRelationshipModel purchaseInvoiceRelationshipModel;
    @Resource
    private EsHelper esHelper;

    public Map<String, Object> getRelationMapForJudgeMoney(boolean isHasPaySheet, boolean isPrePaySheet, boolean isPrePaySheetUnion, boolean isHasPayPlan, String corpid, List<Long> purchaseIds, List<Long> refIds) throws XbbException {
        Map<String, Object> relationMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        String type = InvoiceConstant.PURCHASE;
        Map<String, Object> tempParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        tempParam.put(ParameterConstant.ID_IN,purchaseIds);
        tempParam.put(ParameterConstant.CORPID, corpid);
        List<PurchaseEntityExt> purchaseList = purchaseModel.findEntitys(tempParam);
        int num = 0;
        Double purchaseMoney = 0D;
        Double payPlanMoney = 0D;
        Double paySheetMoney = 0D;
        Map<Long,Double> purchaseUnInvoiceMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Double> purchaseInvoiceMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Double> payPlanInvoiceMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Double> payPlanMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Double> paySheetMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Double> paySheetInvoiceMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Double> purchaseTotalMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Double> payPlanTotalMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Double> paySheetTotalMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //计算合同金额
        for (PurchaseEntityExt purchaseEntityExt : purchaseList) {
            JSONObject dataList = purchaseEntityExt.getData();
            purchaseMoney = Arith.add(purchaseMoney,getDoubleOrDefaultFromFormData(dataList, PurchaseEnum.TOTAL_MONEY.getAttr(), 0D));
            purchaseTotalMoneyMap.put(purchaseEntityExt.getId(),getDoubleOrDefaultFromFormData(dataList,PurchaseEnum.TOTAL_MONEY.getAttr(),0D));
            purchaseUnInvoiceMap.put(purchaseEntityExt.getId(),getDoubleOrDefaultFromFormData(dataList, PurchaseEnum.UN_INVOICE_AMOUNT.getAttr(), 0D));
            purchaseInvoiceMap.put(purchaseEntityExt.getId(),getDoubleOrDefaultFromFormData(dataList, PurchaseEnum.INVOICE_AMOUNT.getAttr(), 0D));
            num++;
        }
        relationMap.put("purchaseNum", num);
        relationMap.put("purchaseId",purchaseIds);
        relationMap.put("purchaseMoney",purchaseMoney);
        relationMap.put("purchaseInvoiceMoney",purchaseInvoiceMap);
        relationMap.put("purchaseUnInvoiceMoney",purchaseUnInvoiceMap);
        relationMap.put("purchaseTotalMoney",purchaseTotalMoneyMap);
        num = 0;
        if (isHasPayPlan) {
            tempParam.put(ParameterConstant.ID_IN, refIds);
            List<PayPlanEntityExt> payPlanList = payPlanModel.findEntitys(tempParam);
            for (PayPlanEntityExt payPlanEntityExt : payPlanList) {
                JSONObject dataList = payPlanEntityExt.getData();
                payPlanMoney += getDoubleOrDefaultFromFormData(dataList, PayPlanEnum.AMOUNT.getAttr(), 0D);
                payPlanMoneyMap.put(payPlanEntityExt.getId(),getDoubleOrDefaultFromFormData(dataList, PayPlanEnum.AMOUNT.getAttr(), 0D));
                payPlanInvoiceMap.put(payPlanEntityExt.getId(),getDoubleOrDefaultFromFormData(dataList, PayPlanEnum.INVOICE_AMOUNT.getAttr(), 0D));
                payPlanTotalMoneyMap.put(payPlanEntityExt.getId(),getDoubleOrDefaultFromFormData(dataList,PayPlanEnum.AMOUNT.getAttr(),0D));
                num++;
            }
            type = InvoiceConstant.PAYPLAN;
            relationMap.put("payPlanId",refIds);
            relationMap.put("payPlanMoney",payPlanMoney);
            relationMap.put("payPlanMoneyMap",payPlanMoneyMap);
            relationMap.put("payPlanInvoiceMoney",payPlanInvoiceMap);
            relationMap.put("payPlanTotalMoney",payPlanTotalMoneyMap);
            relationMap.put("payPlanNum", num);
        }else {
            relationMap.put("payPlanNum", 0);
        }
        if(isHasPaySheet){
            tempParam.put(ParameterConstant.ID_IN, refIds);
            List<PayPlanSheetEntityExt> paymentSheetEntityExtList = payPlanSheetModel.findEntitys(tempParam);
            for(PayPlanSheetEntityExt paySheetEntityExt : paymentSheetEntityExtList){
                JSONObject dataList = paySheetEntityExt.getData();
                paySheetMoney += getDoubleOrDefaultFromFormData(dataList, PaySheetEnum.AMOUNT.getAttr(),0D);
                paySheetMoneyMap.put(paySheetEntityExt.getId(),getDoubleOrDefaultFromFormData(dataList, PaySheetEnum.AMOUNT.getAttr(), 0D));
                paySheetInvoiceMap.put(paySheetEntityExt.getId(),getDoubleOrDefaultFromFormData(dataList, PaySheetEnum.INVOICE_AMOUNT.getAttr(), 0D));
                paySheetTotalMoneyMap.put(paySheetEntityExt.getId(),getDoubleOrDefaultFromFormData(dataList,PaySheetEnum.AMOUNT.getAttr(),0D));
                num++;
            }
            type = InvoiceConstant.PAYSHEET;
            relationMap.put("isPrePaySheet",isPrePaySheet);
            relationMap.put("isPrePaySheetUnion",isPrePaySheetUnion);
            relationMap.put("paySheetId",refIds);
            relationMap.put("paySheetMoney",paySheetMoney);
            relationMap.put("paySheetMoneyMap",paySheetMoneyMap);
            relationMap.put("paySheetInvoiceMoney",paySheetInvoiceMap);
            relationMap.put("paySheetTotalMoney",paySheetTotalMoneyMap);
            relationMap.put("paySheetNum",num);
        }else {
            relationMap.put("paySheetNum",0);
        }
        relationMap.put("type", type);
        return relationMap;
    }


    public void invoiceAmountJudgment(String corpid, Long purchaseInvoiceId, Double invoiceMoney, Map<String, Object> relationIdIn, Integer isImport, Integer isCover, Integer isRestore, JSONArray amountDetail) throws XbbException {
        // 总采购合同金额
        Double totalPurchaseMoney = 0D;
        // 已开金额
        Double alreadyMoney = 0D;
        //采购合同已开金额
        Double purchaseAlreadMoney = 0D;
        // 总付款金额
        Double totalPayPlanMoney = 0D;
        // 总回款单金额
        Double totalPaySheetMoney= 0D;
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(ParameterConstant.PURCHASE_INVOICE_ID,purchaseInvoiceId);
        param.put(ParameterConstant.CORPID, corpid);
        param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        // 发票关联表数据
        List<PurchaseInvoiceRelationshipEntity> relations;
        //非新建的情况
        if (!Objects.equals(purchaseInvoiceId, 0L)) {
            relations = purchaseInvoiceRelationshipModel.findEntitys(param);
            if (relations.isEmpty()) {
                return;
            }
        }
        param.remove(ParameterConstant.PURCHASE_INVOICE_ID);
        param.put(ParameterConstant.IS_CANCEL, BasicConstant.ZERO);
        param.put(ParameterConstant.FLOW_STATUS_IN, Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType()));
        // 判断操作类型和是否合并开票
        Map<String, Object> map = judgeOperationAndMerge(relationIdIn,purchaseInvoiceId);
        // 是否合并开票
        boolean isMerge = (boolean) map.getOrDefault("isMerge", false);
        // 操作类型
        String operation = map.getOrDefault("operation", "").toString();
        // 类型
        String  type = map.getOrDefault("type", "").toString();
        boolean isPrePaySheet = false;
        boolean isPrePaySheetUnion = false;
        if(relationIdIn.containsKey(InvoiceConstant.IS_PRE_PAY_SHEET)){
            isPrePaySheet = (boolean) relationIdIn.get(InvoiceConstant.IS_PRE_PAY_SHEET);
        }
        if(relationIdIn.containsKey(InvoiceConstant.IS_PRE_PAY_SHEET_UNION)){
            isPrePaySheetUnion = (boolean) relationIdIn.get(InvoiceConstant.IS_PRE_PAY_SHEET_UNION);
        }
        if (!isMerge) {
            // 单次开票需要计算是否超出
            Long payPlanId = 0L;
            Long paySheetId = 0L;
            List<Map<String, Object>> purchaseSumMoney = null;
            List<Map<String,Object>> payPlanOrPaySheetSumMoney = null;
            // 回款开票既要确认开票金额是否大于所在合同剩余可开金额,有要判断开票金额是否大于所在回款剩余可开金额;存在合同已开完而回款单未开过等特殊情况
            if (InvoiceConstant.PURCHASE.equals(type) || InvoiceConstant.PAYPLAN.equals(type) || InvoiceConstant.PAYSHEET.equals(type) || Objects.equals(isImport,BasicConstant.ONE)) {
                List<Long> purchaseIds = new ArrayList<>();
                // 新建编辑
                if (InvoiceConstant.NEW.equals(operation) || InvoiceConstant.EDIT.equals(operation)) {
                    if (InvoiceConstant.EDIT.equals(operation)) {
                        param.put("purchaseInvoiceIdNot", purchaseInvoiceId);
                    }
                    if(!isPrePaySheet) {
                        if (relationIdIn.get(PurchaseInvoiceEnum.PURCHASE_ID.getSaasAttr()) instanceof List) {
                            purchaseIds = (List<Long>) relationIdIn.get(PurchaseInvoiceEnum.PURCHASE_ID.getSaasAttr());
                        }
                        //关联表合同Id
                        if (purchaseIds.get(0) > BasicConstant.ZERO) {
                            param.put(PurchaseInvoiceEnum.PURCHASE_ID.getSaasAttr(), purchaseIds.get(0));
                        }
                        totalPurchaseMoney = MoneyUtil.parseDouble(relationIdIn.get("purchaseMoney"));
                        purchaseSumMoney = purchaseInvoiceRelationshipModel.getSumMoneyOfPurchase(param);
                    }
                }
                if (InvoiceConstant.PAYPLAN.equals(type)) {
                    if (operation.equals(InvoiceConstant.NEW) || operation.equals(InvoiceConstant.EDIT)) {
                        if(relationIdIn.get(PurchaseInvoiceEnum.PAY_PLAN_ID.getSaasAttr()) instanceof List) {
                            payPlanId = ((List<Long>) relationIdIn.get("payPlanId")).get(0);
                        }
                        param.put(PurchaseInvoiceEnum.PAY_PLAN_ID.getSaasAttr(),payPlanId);
                    }
                    totalPayPlanMoney = MoneyUtil.parseDouble(relationIdIn.get("payPlanMoney"));
                    payPlanOrPaySheetSumMoney = purchaseInvoiceRelationshipModel.getSumMoneyOfPayPlan(param);
                }else if(InvoiceConstant.PAYSHEET.equals(type)){
                    if(operation.equals(InvoiceConstant.NEW) || operation.equals(InvoiceConstant.EDIT)){
                        if(relationIdIn.get(PurchaseInvoiceEnum.PAY_SHEET_ID.getSaasAttr()) instanceof List) {
                            paySheetId = ((List<Long>) relationIdIn.get("paySheetId")).get(0);
                        }
                        param.put(PurchaseInvoiceEnum.PAY_SHEET_ID.getSaasAttr(),paySheetId);
                    }
                    totalPaySheetMoney = MoneyUtil.parseDouble(relationIdIn.get("paySheetMoney"));
                    payPlanOrPaySheetSumMoney = purchaseInvoiceRelationshipModel.getSumMoneyOfPaySheet(param);
                }
                //回款所关联的合同已开金额
                if (CollectionsUtil.isEmpty(payPlanOrPaySheetSumMoney)) {
                    alreadyMoney = 0D;
                } else {
                    alreadyMoney = MoneyUtil.parseDouble(payPlanOrPaySheetSumMoney.get(0).get("allMoney"));
                }
            }
            if(!isPrePaySheet) {
                if (CollectionsUtil.isEmpty(purchaseSumMoney)) {
                    purchaseAlreadMoney = 0D;
                }else {
                    purchaseAlreadMoney =  MoneyUtil.parseDouble(purchaseSumMoney.get(0).get("allMoney"));
                }
                if (Arith.sub(invoiceMoney, Arith.sub(totalPurchaseMoney, purchaseAlreadMoney)) > ConfigConstant.amountAccuracy) {
                    throw new XbbException(InvoiceErrorCodeEnum.APT_ERROR_216001);
                }
            }
            if (InvoiceConstant.PAYPLAN.equals(type)) {
                //如果是回款开票,在判断完开票金额小于合同可开金额后，还需与回款可开金额进行比较
                if (Arith.sub(invoiceMoney, Arith.sub(totalPayPlanMoney, alreadyMoney)) > ConfigConstant.amountAccuracy) {
                    throw new XbbException(InvoiceErrorCodeEnum.APT_ERROR_216002);
                }
            }else if(InvoiceConstant.PAYSHEET.equals(type)){
                if(Arith.sub(invoiceMoney,Arith.sub(totalPaySheetMoney,alreadyMoney)) > ConfigConstant.amountAccuracy){
                    throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_216022);
                }
            }
        } else {
            Map<Long,Double> purchaseTotalInvoiceMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<Long,Double> payPlanOrPaySheetTotalInvoiceMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<Long,Double> purchaseReadyInvoiceMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<Long,Double> payPlanOrPaySheetReadyInvoiceMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if (InvoiceConstant.PURCHASE.equals(type)) {
                //新增编辑审批 合同合并开票
                if (InvoiceConstant.EDIT.equals(operation)) {
                    param.put("purchaseInvoiceIdNot", purchaseInvoiceId);
                }
                List<Long> purchaseIds = null;
                int purchaseIdNum = 0;
                if (relationIdIn.get(PurchaseInvoiceEnum.PURCHASE_ID.getSaasAttr()) instanceof List) {
                    purchaseIds = (List<Long>) relationIdIn.get(PurchaseInvoiceEnum.PURCHASE_ID.getSaasAttr());
                    param.put("purchaseIdIn", purchaseIds);
                    purchaseIdNum = purchaseIds.size();
                }
                if (relationIdIn.get(InvoiceConstant.PURCHASE_TOTAL_MONEY) instanceof Map) {
                    purchaseTotalInvoiceMoneyMap = (Map<Long, Double>) relationIdIn.get(InvoiceConstant.PURCHASE_TOTAL_MONEY);
                }
                //获取已开的发票金额
                getRefIdAndAmount(param, purchaseReadyInvoiceMoneyMap,PurchaseInvoiceEnum.PURCHASE_ID);

                if (Objects.equals(isImport, BasicConstant.ONE)) {
                    getCountInvoice(param,relationIdIn, invoiceMoney, InvoiceConstant.PURCHASE_TOTAL_MONEY,isCover);
                }else{
                    if(Objects.equals(isRestore, BasicConstant.ONE)){
                        param.remove("purchaseInvoiceIdNot");
                        param.put("purchaseInvoiceId",purchaseInvoiceId);
                        //作废后还原逻辑，去数据库取金额明细
                        param.put(ParameterConstant.IS_CANCEL, BasicConstant.ONE);
                        List<PurchaseInvoiceRelationshipEntity> relationshipEntities = purchaseInvoiceRelationshipModel.findEntitys(param);
                        for(PurchaseInvoiceRelationshipEntity purchaseInvoiceRelationshipEntity : relationshipEntities){
                            Long purchaseId = purchaseInvoiceRelationshipEntity.getPurchaseId();
                            Double purchaseInvoice = purchaseInvoiceRelationshipEntity.getMoney();
                            InvoiceUtil.checkContractInvoiceAmountHandle(purchaseReadyInvoiceMoneyMap,purchaseTotalInvoiceMoneyMap,purchaseId,purchaseInvoice);
                        }
                    }else {
                        for(int i=0;i<amountDetail.size();i++){
                            JSONObject amountObject = amountDetail.getJSONObject(i);
                            JSONObject purchaseObject = amountObject.getJSONArray(InvoiceConstant.PURCHASE).getJSONObject(0);
                            Long purchaseId = purchaseObject.getLong(BasicConstant.ID);
                            Double purchaseInvoiceMoney = amountObject.getDouble(InvoiceConstant.INVOICE_AMOUNT);
                            InvoiceUtil.checkContractInvoiceAmountHandle(purchaseReadyInvoiceMoneyMap,purchaseTotalInvoiceMoneyMap,purchaseId,purchaseInvoiceMoney);
                        }
                    }
                }
            }
            if (InvoiceConstant.PAYPLAN.equals(type)) {
                //如果是回款开票,在判断完开票金额小于合同可开金额后，还需与回款可开金额进行比较
                if (InvoiceConstant.EDIT.equals(operation)) {
                    param.put("purchaseInvoiceIdNot", purchaseInvoiceId);
                }
                List<Long> payPlanIds = null;
                List<Long> purchaseIds = null;
                int payPlanIdNum = 0;
                if(relationIdIn.get(PurchaseInvoiceEnum.PAY_PLAN_ID.getSaasAttr()) instanceof List){
                    payPlanIds = (List<Long>) relationIdIn.get(PurchaseInvoiceEnum.PAY_PLAN_ID.getSaasAttr());
                    param.put("payPlanIdIn",payPlanIds);
                    payPlanIdNum = payPlanIds.size();
                }
                if(relationIdIn.get(PurchaseInvoiceEnum.PURCHASE_ID.getSaasAttr()) instanceof List){
                    purchaseIds = (List<Long>) relationIdIn.get(PurchaseInvoiceEnum.PURCHASE_ID.getSaasAttr());
                }
                if(relationIdIn.get(InvoiceConstant.PAYPLAN_TOTAL_MONEY) instanceof Map){
                    payPlanOrPaySheetTotalInvoiceMoneyMap = (Map<Long,Double>) relationIdIn.get(InvoiceConstant.PAYPLAN_TOTAL_MONEY);
                }
                if(relationIdIn.get(InvoiceConstant.PURCHASE_TOTAL_MONEY) instanceof Map){
                    purchaseTotalInvoiceMoneyMap = (Map<Long,Double>) relationIdIn.get(InvoiceConstant.PURCHASE_TOTAL_MONEY);
                }
                //获取已开的发票金额
                param.remove("payPlanIdIn");
                param.put("purchaseIdIn",purchaseIds);
                getRefIdAndAmount(param,purchaseReadyInvoiceMoneyMap,PurchaseInvoiceEnum.PURCHASE_ID);
                param.put("payPlanIdIn",payPlanIds);
                getRefIdAndAmount(param,payPlanOrPaySheetReadyInvoiceMoneyMap,PurchaseInvoiceEnum.PAY_PLAN_ID);
                if(Objects.equals(isImport,BasicConstant.ONE)){
                    //批量走 这个
                    getCountInvoice(param,relationIdIn,invoiceMoney,InvoiceConstant.PAYPLAN_TOTAL_MONEY,isCover);
                }else {
                    if(Objects.equals(isRestore, BasicConstant.ONE)){
                        param.remove("purchaseInvoiceIdNot");
                        param.put("purchaseInvoiceId",purchaseInvoiceId);
                        //作废后还原逻辑，去数据库取金额明细
                        param.put(ParameterConstant.IS_CANCEL, BasicConstant.ONE);
                        List<PurchaseInvoiceRelationshipEntity> relationshipEntities = purchaseInvoiceRelationshipModel.findEntitys(param);
                        for(PurchaseInvoiceRelationshipEntity purchaseInvoiceRelationshipEntity : relationshipEntities){
                            Long purchaseId = purchaseInvoiceRelationshipEntity.getPurchaseId();
                            Long payPlanId = purchaseInvoiceRelationshipEntity.getPayPlanId();
                            Double payPlanInvoiceMoney = purchaseInvoiceRelationshipEntity.getMoney();
                            InvoiceUtil.checkPaymentOrSheetInvoiceAmountHandle(purchaseReadyInvoiceMoneyMap,purchaseTotalInvoiceMoneyMap,payPlanOrPaySheetReadyInvoiceMoneyMap,payPlanOrPaySheetTotalInvoiceMoneyMap,purchaseId,payPlanId,payPlanInvoiceMoney,XbbRefTypeEnum.PURCHASE_INVOICE.getCode(),PayRelationshipEnum.PAY_PLAN.getCode(),false,false);
                        }
                    }else {
                        for(int i=0;i<amountDetail.size();i++){
                            JSONObject amountObject = amountDetail.getJSONObject(i);
                            JSONObject purchaseObject = amountObject.getJSONArray(InvoiceConstant.PURCHASE).getJSONObject(0);
                            JSONObject payPlanObject = amountObject.getJSONArray(InvoiceConstant.PAYPLAN).getJSONObject(0);
                            Long purchaseId = purchaseObject.getLong(BasicConstant.ID);
                            Long payPlanId = payPlanObject.getLong(BasicConstant.ID);
                            Double payPlanInvoiceMoney = amountObject.getDouble(InvoiceConstant.INVOICE_AMOUNT);
                            InvoiceUtil.checkPaymentOrSheetInvoiceAmountHandle(purchaseReadyInvoiceMoneyMap,purchaseTotalInvoiceMoneyMap,payPlanOrPaySheetReadyInvoiceMoneyMap,payPlanOrPaySheetTotalInvoiceMoneyMap,purchaseId,payPlanId,payPlanInvoiceMoney,XbbRefTypeEnum.PURCHASE_INVOICE.getCode(),PayRelationshipEnum.PAY_PLAN.getCode(),false,false);
                        }
                    }
                }
            }else if(InvoiceConstant.PAYSHEET.equals(type)){
                //新增编辑 回款合并开票
                if (InvoiceConstant.EDIT.equals(operation)) {
                    param.put("purchaseInvoiceIdNot", purchaseInvoiceId);
                }
                List<Long> paySheetIds = null;
                List<Long> purchaseIds = null;
                int paySheetIdNum = 0;
                if(relationIdIn.get(PurchaseInvoiceEnum.PAY_SHEET_ID.getSaasAttr()) instanceof List){
                    paySheetIds = (List<Long>) relationIdIn.get(InvoiceConstant.PAY_SHEET_ID);
                    param.put("paymentSheetIdIn",paySheetIds);
                    paySheetIdNum = paySheetIds.size();
                }
                if(relationIdIn.get(PurchaseInvoiceEnum.PURCHASE_ID.getSaasAttr()) instanceof List){
                    purchaseIds = (List<Long>) relationIdIn.get(InvoiceConstant.PURCHASE_ID);
                }
                if(relationIdIn.get(InvoiceConstant.PAYSHEET_TOTAL_MONEY) instanceof Map){
                    payPlanOrPaySheetTotalInvoiceMoneyMap = (Map<Long,Double>) relationIdIn.get(InvoiceConstant.PAYSHEET_TOTAL_MONEY);
                }
                if(relationIdIn.get(InvoiceConstant.PURCHASE_TOTAL_MONEY) instanceof Map){
                    purchaseTotalInvoiceMoneyMap = (Map<Long,Double>) relationIdIn.get(InvoiceConstant.PURCHASE_TOTAL_MONEY);
                }

                //获取已开的发票金额
                param.remove("paySheetIdIn");
                if(!isPrePaySheet && !isPrePaySheetUnion) {
                    param.put("purchaseIdIn",purchaseIds);
                    getRefIdAndAmount(param,purchaseReadyInvoiceMoneyMap,PurchaseInvoiceEnum.PURCHASE_ID);
                }
                param.put("paySheetIdIn",paySheetIds);
                getRefIdAndAmount(param,payPlanOrPaySheetReadyInvoiceMoneyMap,PurchaseInvoiceEnum.PAY_SHEET_ID);

                if(Objects.equals(isImport,BasicConstant.ONE)){
                    //去掉之前的id
                    getCountInvoice(param,relationIdIn,invoiceMoney,InvoiceConstant.PAYSHEET_TOTAL_MONEY,isCover);
                }else{
                    if(Objects.equals(isRestore, BasicConstant.ONE)){
                        param.remove("purchaseInvoiceIdNot");
                        param.put("purchaseInvoiceId",purchaseInvoiceId);
                        //作废后还原逻辑，去数据库取金额明细
                        param.put(ParameterConstant.IS_CANCEL, BasicConstant.ONE);
                        List<PurchaseInvoiceRelationshipEntity> relationshipEntities = purchaseInvoiceRelationshipModel.findEntitys(param);
                        for(PurchaseInvoiceRelationshipEntity purchaseInvoiceRelationshipEntity : relationshipEntities){
                            Long purchaseId = purchaseInvoiceRelationshipEntity.getPurchaseId();
                            Long paySheetId = purchaseInvoiceRelationshipEntity.getPaySheetId();
                            Double paySheetInvoiceMoney = purchaseInvoiceRelationshipEntity.getMoney();
                            InvoiceUtil.checkPaymentOrSheetInvoiceAmountHandle(purchaseReadyInvoiceMoneyMap,purchaseTotalInvoiceMoneyMap,payPlanOrPaySheetReadyInvoiceMoneyMap,payPlanOrPaySheetTotalInvoiceMoneyMap,purchaseId,paySheetId,paySheetInvoiceMoney,XbbRefTypeEnum.PURCHASE_INVOICE.getCode(),PayRelationshipEnum.PAY_SHEET.getCode(),isPrePaySheet,isPrePaySheetUnion);
                        }
                    }else {
                        for (int i = 0; i < amountDetail.size(); i++) {
                            JSONObject amountObject = amountDetail.getJSONObject(i);
                            Long purchaseId = 0L;
                            if(!isPrePaySheetUnion) {
                                JSONObject purchaseObject = amountObject.getJSONArray(InvoiceConstant.PURCHASE).getJSONObject(0);
                                purchaseId = purchaseObject.getLong(BasicConstant.ID);
                            }
                            JSONObject paySheetObject = amountObject.getJSONArray(InvoiceConstant.PAYSHEET).getJSONObject(0);
                            Long paySheetId = paySheetObject.getLong(BasicConstant.ID);
                            Double paySheetInvoiceMoney = amountObject.getDouble(InvoiceConstant.INVOICE_AMOUNT);
                            InvoiceUtil.checkPaymentOrSheetInvoiceAmountHandle(purchaseReadyInvoiceMoneyMap,purchaseTotalInvoiceMoneyMap,payPlanOrPaySheetReadyInvoiceMoneyMap,payPlanOrPaySheetTotalInvoiceMoneyMap,purchaseId,paySheetId,paySheetInvoiceMoney,XbbRefTypeEnum.PURCHASE_INVOICE.getCode(),PayRelationshipEnum.PAY_SHEET.getCode(),isPrePaySheet,isPrePaySheetUnion);
                        }
                    }
                }
            }
        }
    }
    private void getRefIdAndAmount(Map<String,Object> param,Map<Long,Double> readyInvoiceMoneyMap,PurchaseInvoiceEnum purchaseInvoiceEnum){
        List<PurchaseInvoiceRelationshipEntity> purchaseSumList = purchaseInvoiceRelationshipModel.findEntitys(param);
        Long refId = 0L;
        for(PurchaseInvoiceRelationshipEntity purchaseInvoiceRelationshipEntity : purchaseSumList){
            if(Objects.equals(purchaseInvoiceEnum,PurchaseInvoiceEnum.PURCHASE_ID)){
                if(Objects.nonNull(purchaseInvoiceRelationshipEntity.getPurchaseId())){
                    refId = purchaseInvoiceRelationshipEntity.getPurchaseId();
                }
            }else if(Objects.equals(purchaseInvoiceEnum,PurchaseInvoiceEnum.PAY_PLAN_ID)){
                if(Objects.nonNull(purchaseInvoiceRelationshipEntity.getPayPlanId())){
                    refId = purchaseInvoiceRelationshipEntity.getPayPlanId();
                }
            }else if(Objects.equals(purchaseInvoiceEnum,PurchaseInvoiceEnum.PAY_SHEET_ID)){
                if(Objects.nonNull(purchaseInvoiceRelationshipEntity.getPaySheetId())){
                    refId = purchaseInvoiceRelationshipEntity.getPaySheetId();
                }
            }
            if(readyInvoiceMoneyMap.containsKey(refId)){
                readyInvoiceMoneyMap.put(refId,readyInvoiceMoneyMap.get(refId) + purchaseInvoiceRelationshipEntity.getMoney());
            }else {
                readyInvoiceMoneyMap.put(refId,purchaseInvoiceRelationshipEntity.getMoney());
            }
        }
    }
    /**
     * 判断操作类型和是否合并开票
     *
     * @param relationIdIn map
     * @param purchaseInvoiceId    发票id
     * @return map
     */
    public Map<String, Object> judgeOperationAndMerge(Map<String, Object> relationIdIn, Long purchaseInvoiceId) {
        Integer purchaseNum = (Integer) relationIdIn.get("purchaseNum");
        Integer payPlanNum = (Integer) relationIdIn.get("payPlanNum");
        Integer paySheetNum = (Integer) relationIdIn.get("paySheetNum");
        Map<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 操作类型
        String operation = "";
        // 是否合并开票
        boolean isMerge = false;
        if (purchaseInvoiceId == 0L) {
            //新建的情况
            operation = InvoiceConstant.NEW;
            if (purchaseNum > BasicConstant.ONE || payPlanNum > BasicConstant.ONE
                    || paySheetNum > BasicConstant.ONE) {
                // 根据新建修改的合同或回款数判断是否为合并开票
                isMerge = true;
            }
        } else if (purchaseInvoiceId > 0L) {
            operation = InvoiceConstant.EDIT;
            if (purchaseNum > BasicConstant.ONE || payPlanNum > BasicConstant.ONE || paySheetNum > BasicConstant.ONE) {
                // 根据新建修改的合同或回款数判断是否为合并开票
                isMerge = true;
            }
        }

        if(purchaseNum>0){
            String type = InvoiceConstant.PURCHASE;
            if(payPlanNum>0){
                type = InvoiceConstant.PAYPLAN;
            }
            if(paySheetNum>0){
                type = InvoiceConstant.PAYSHEET;
            }
            map.put("type",type);
        }else if(paySheetNum >0){
            map.put("type",InvoiceConstant.PAYSHEET);
        }
        map.put("operation", operation);
        map.put("isMerge", isMerge);
        return map;
    }


    private void getCountInvoice(Map<String, Object> param,Map<String,Object> relationIdIn, Double invoiceMoney, String key, Integer isCover) throws XbbException{
        //导入不用再去判断合同有没有开过票,直接去校验金额
        if(Objects.equals(key,InvoiceConstant.PAYPLAN_TOTAL_MONEY)){
            param.remove("payPlanIdIn");
        }
        if(Objects.equals(key,InvoiceConstant.PAYSHEET_TOTAL_MONEY)){
            param.remove("paySheetIdIn");
        }
        Double purchaseMoney = MoneyUtil.parseDouble(relationIdIn.get(InvoiceConstant.PURCHASE_MONEY));
        Double payPlanMoney = MoneyUtil.parseDouble(relationIdIn.get(InvoiceConstant.PAYPLAN_MONEY));
        Double paySheetMoney = MoneyUtil.parseDouble(relationIdIn.get(InvoiceConstant.PAYSHEET_MONEY));
        if(Objects.equals(key,InvoiceConstant.PURCHASE_TOTAL_MONEY)) {
            if (invoiceMoney > purchaseMoney) {
                throw new XbbException(InvoiceErrorCodeEnum.APT_ERROR_216001);
            }
            commonCheckContractInvoiceAmount(relationIdIn,invoiceMoney,isCover,param,purchaseMoney);
        }else if(Objects.equals(key,InvoiceConstant.PAYPLAN_TOTAL_MONEY)){
            if (invoiceMoney > payPlanMoney) {
                throw new XbbException(InvoiceErrorCodeEnum.APT_ERROR_217013);
            }
            //合并开票时去效验一下合同的金额
            commonCheckContractInvoiceAmount(relationIdIn,invoiceMoney,isCover,param,purchaseMoney);
        }else if(Objects.equals(key,InvoiceConstant.PAYSHEET_TOTAL_MONEY)){
            if (invoiceMoney > paySheetMoney) {
                throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_217014);
            }
            commonCheckContractInvoiceAmount(relationIdIn,invoiceMoney,isCover,param,purchaseMoney);
        }
        if(Objects.equals(key,InvoiceConstant.PURCHASE_TOTAL_MONEY)) {
            if (invoiceMoney < purchaseMoney) {
                throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_217015);
            }
        }else if(Objects.equals(key,InvoiceConstant.PAYPLAN_TOTAL_MONEY)){
            if (invoiceMoney < payPlanMoney) {
                throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_217016);
            }
        }else if(Objects.equals(key,InvoiceConstant.PAYSHEET_TOTAL_MONEY)){
            if (invoiceMoney < paySheetMoney) {
                throw new XbbException(InvoiceErrorCodeEnum.API_ERROR_217017);
            }
        }
    }

    public Map<Long, Double> getRedTotalMoneyByIdIn(List<Long> originIdIn,List<Long> negIdIn, String corpid) throws XbbException {
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termsQuery(StringConstant.JSON_DATA + StringConstant.POINT + PurchaseInvoiceEnum.ORIGIN_ID.getAttr(), originIdIn));
        boolQueryBuilder.filter(termsQuery(FieldTypeEnum.FLOW_STATUS.getAlias(), Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType())));
        boolQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD , corpid));
        boolQueryBuilder.filter(termQuery(ParameterConstant.DEL, DelEnum.NORMAL.getDel()));
        if (CollectionsUtil.isNotEmpty(negIdIn)){
            boolQueryBuilder.filter(boolQuery().mustNot(termsQuery(FieldTypeEnum.DATAID.getAlias(), negIdIn)));
        }
        List<String> fieldList = new ArrayList<>();
        fieldList.add(PurchaseInvoiceEnum.getAttrConnectData(PurchaseInvoiceEnum.ORIGIN_ID));
        fieldList.add(PurchaseInvoiceEnum.getAttrConnectData(PurchaseInvoiceEnum.TOTAL_MONEY));
        List<PaasFormDataEntityExt> originInvoiceList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PURCHASE_INVOICE, boolQueryBuilder, PaasFormDataEntityExt.class, fieldList);
        Map<Long, Double> redMoneyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Long originId;
        Double money;
        for (PaasFormDataEntityExt paasFormDataEntityExt : originInvoiceList) {
            originId = FastJsonHelper.getLongOrDefaultFromFormData(paasFormDataEntityExt.getData(), PurchaseInvoiceEnum.ORIGIN_ID.getAttr(), 0L);
            money = getDoubleOrDefaultFromFormData(paasFormDataEntityExt.getData(), PurchaseInvoiceEnum.TOTAL_MONEY.getAttr(), 0D);
            if (redMoneyMap.containsKey(originId)) {
                money = redMoneyMap.get(originId) + money;
            }
            redMoneyMap.put(originId, money);
        }
        return redMoneyMap;
    }

    /**
     * 导入时效验合同的金额
     * @param relationIdIn
     * @param invoiceMoney
     * @throws XbbException
     */
    private void commonCheckContractInvoiceAmount(Map<String,Object> relationIdIn,Double invoiceMoney,Integer isCover,Map<String,Object> param,Double purchaseAmount) throws XbbException{
        Double purchaseUnInvoiceMoney = 0D;
        try {
            if(Objects.equals(isCover,BasicConstant.ONE)){
                double purchaseReadyInvoiceMoney = 0D;
                double purchaseTotalInvoiceMoney = purchaseAmount;
                List<PurchaseInvoiceRelationshipEntity> purchaseInvoiceRelationshipEntities = purchaseInvoiceRelationshipModel.findEntitys(param);
                Set<Long> originIdList = new HashSet<>();
                if(CollectionsUtil.isNotEmpty(purchaseInvoiceRelationshipEntities)) {
                    for (PurchaseInvoiceRelationshipEntity invoiceRelationshipEntity : purchaseInvoiceRelationshipEntities) {
                        purchaseReadyInvoiceMoney = Arith.add(purchaseReadyInvoiceMoney, invoiceRelationshipEntity.getMoney());
                        originIdList.add(invoiceRelationshipEntity.getPurchaseInvoiceId());
                    }
                }
                String corpid = (String)param.getOrDefault("corpid","0");
                Map<Long, Double> redInvoiceMap = getRedTotalMoneyByIdIn(new ArrayList<Long>(originIdList),null,corpid);
                List<Double> contractRedInvoiceMoneyList= new ArrayList<>(redInvoiceMap.values());
                for (Double aDouble : contractRedInvoiceMoneyList) {
                    purchaseReadyInvoiceMoney = Arith.add(purchaseReadyInvoiceMoney,aDouble);
                }
                purchaseUnInvoiceMoney = Arith.sub(purchaseTotalInvoiceMoney,purchaseReadyInvoiceMoney);
            }else {
                Map<Long,Double> purchaseUnInvoiceMoneyMap = (Map<Long, Double>) relationIdIn.get(InvoiceConstant.PURCHASE_UN_INVOICE_MONEY);
                List<Double> purchaseUnInvoiceMoneyList= new ArrayList<>(purchaseUnInvoiceMoneyMap.values());
                for (Double aDouble : purchaseUnInvoiceMoneyList) {
                    purchaseUnInvoiceMoney = Arith.add(purchaseUnInvoiceMoney,aDouble);
                }
            }
        } catch (Exception e) {
            LOG.error("",e);
        }
        if(invoiceMoney > purchaseUnInvoiceMoney){
            throw new XbbException(InvoiceErrorCodeEnum.APT_ERROR_216001);
        }
    }
}
